//*******************************************************************
//glfont2.cpp -- glFont Version 2.0 implementation
//Copyright (c) 1998-2002 Brad Fish
//See glfont.html for terms of use
//May 14, 2002
//*******************************************************************

//STL headers
#include <string>
using namespace std;


#ifdef _WIN32 /* Stupid Windows needs to include windows.h before gl.h */
#undef FAR
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#endif
#include "gl.h"

//glFont header
#include "glfont2.h"
using namespace glfont;


//*******************************************************************
//GLFont Class Implementation
//*******************************************************************
GLFont::GLFont ()
{
	//Initialize header to safe state
	tex = -1;
	header.tex_width = 0;
	header.tex_height = 0;
	defChar.adv = 0;
	defChar.ox = 0;
	defChar.oy = 0;
	defChar.tx1 = 0;
	defChar.ty1 = 0;
	defChar.tdx = 0;
	defChar.tdy = 0;
}
//*******************************************************************
GLFont::~GLFont ()
{
	//Destroy the font
	Destroy();
}

bool GLFont::Create(unsigned int tex, unsigned int tex_width, unsigned int tex_height, short font_height, unsigned char encodeing)
{
	header.chars.clear();
	header.encoding = encodeing;
	header.tex_width = tex_width;
	header.tex_height = tex_height;
	header.font_height = font_height;
	this->tex = tex;
	return true;
}

void GLFont::AddChar(int id, const GLFont::GLFontChar& glChar)
{
	if (id < 0)
		defChar = glChar;
	else
		header.chars[id] = glChar;
}

//*******************************************************************
void GLFont::Destroy (void)
{
	//Delete the character array if necessary
	header.chars.clear();
}
//*******************************************************************
void GLFont::Begin (void)
{
#ifdef BBGE_BUILD_OPENGL
	//Bind to font texture
	glBindTexture(GL_TEXTURE_2D, tex);
#endif
}

void GLFont::DrawString(
	const char* text, float scalar, float x,
	float y, const float* top_color, const float* bottom_color, float alpha, float lastAlpha)
{
	GLFontChar* glfont_char;
	float width, height;
	float ox, oy;
	float tx2, ty2;

	//Begin rendering quads
	glBegin(GL_QUADS);

	int sz = GetTextLength(text);

	float a = 0;
	//Loop through characters
	for (int i = 0; i < sz;)
	{
		//Make sure character is in range
		int charId = GetTextChar(text, i, &i);
		glfont_char = GetChar(charId);
		if (glfont_char == 0) glfont_char = &defChar;

		tx2 = glfont_char->tx1 + float(glfont_char->tdx) / (float)header.tex_width;
		ty2 = glfont_char->ty1 + float(glfont_char->tdy) / (float)header.tex_height;
		//Get width and height
		width = float(glfont_char->tdx) * scalar;
		height = float(glfont_char->tdy) * scalar;
		ox = float(glfont_char->ox) * scalar;
		oy = float(glfont_char->oy) * scalar;

		if (i == (sz - 1))
			a = alpha * lastAlpha;
		else
			a = alpha;

		//Specify colors, vertices, and texture coordinates
		glColor4f(top_color[0], top_color[1], top_color[2], a);
		glTexCoord2f(glfont_char->tx1, glfont_char->ty1);
		glVertex3f(x + ox, y + oy, 0.0F);
		glTexCoord2f(tx2, glfont_char->ty1);
		glVertex3f(x + width + ox, y + oy, 0.0F);
		glColor4f(bottom_color[0], bottom_color[1], bottom_color[2], a);
		glTexCoord2f(tx2, ty2);
		glVertex3f(x + width + ox, y + height + oy, 0.0F);
		glTexCoord2f(glfont_char->tx1, ty2);
		glVertex3f(x + ox, y + height + oy, 0.0F);

		//Move to next character
		x += float(glfont_char->adv) * scalar;
	}

	//Stop rendering quads
	glEnd();
}
////*******************************************************************
//void GLFont::GetStringSize (const std::string &text, std::pair<int, int> *size)
//{
//	unsigned int i;
//	unsigned int c;
//	GLFontChar *glfont_char;
//	float width;
//	
//	//debugLog("size->second");
//	//Height is the same for now...might change in future
//	size->second = (int)(header.chars[header.start_char].dy *
//		header.tex_height);
//
//	//Calculate width of string
//	width = 0.0F;
//	for (i = 0; i < text.size(); i++)
//	{
//		//Make sure character is in range
//		c = (unsigned char)text[i];
//		
//		if (c < header.start_char || c > header.end_char)
//			continue;
//
//		//Get pointer to glFont character
//		glfont_char = &header.chars[c - header.start_char];
//
//		//Get width and height
//		width += glfont_char->dx * header.tex_width;		
//	}
//
//	//Save width
//	//debugLog("size first");
//	size->first = (int)width;
//	
//	//debugLog("done");
//}

int GLFont::DecodeUTF8(const char* encodedBuffer, unsigned int* outLength)
{
	const unsigned char* buf = (const unsigned char*)encodedBuffer;

	int value = 0;
	int length = -1;
	unsigned char byte = buf[0];
	if ((byte & 0x80) == 0)
	{
		// This is the only byte
		if (outLength) *outLength = 1;
		return byte;
	}
	else if ((byte & 0xE0) == 0xC0)
	{
		// There is one more byte
		value = int(byte & 0x1F);
		length = 2;

		// The value at this moment must not be less than 2, because 
		// that should have been encoded with one byte only.
		if (value < 2)
			length = -1;
	}
	else if ((byte & 0xF0) == 0xE0)
	{
		// There are two more bytes
		value = int(byte & 0x0F);
		length = 3;
	}
	else if ((byte & 0xF8) == 0xF0)
	{
		// There are three more bytes
		value = int(byte & 0x07);
		length = 4;
	}

	int n = 1;
	for (; n < length; n++)
	{
		byte = buf[n];
		if ((byte & 0xC0) == 0x80)
			value = (value << 6) + int(byte & 0x3F);
		else
			break;
	}

	if (n == length)
	{
		if (outLength) *outLength = (unsigned)length;
		return value;
	}

	// The byte sequence isn't a valid UTF-8 byte sequence.
	return -1;
}

int GLFont::DecodeUTF16(const char* encodedBuffer, unsigned int* outLength, unsigned char byteOrder)
{
	const unsigned char* buf = (const unsigned char*)encodedBuffer;
	int value = 0;
	if (byteOrder == LITTLE_ENDIAN)
	{
		value += buf[0];
		value += (unsigned int)(buf[1]) << 8;
	}
	else
	{
		value += buf[1];
		value += (unsigned int)(buf[0]) << 8;
	}

	if (value < 0xD800 || value > 0xDFFF)
	{
		if (outLength) *outLength = 2;
		return value;
	}
	else if (value < 0xDC00)
	{
		// We've found the first surrogate word
		value = ((value & 0x3FF) << 10);

		// Read the second surrogate word
		int value2 = 0;
		if (byteOrder == LITTLE_ENDIAN)
		{
			value2 += buf[2];
			value2 += (unsigned int)(buf[3]) << 8;
		}
		else
		{
			value2 += buf[3];
			value2 += (unsigned int)(buf[2]) << 8;
		}

		// The second surrogate word must be in the 0xDC00 - 0xDFFF range
		if (value2 < 0xDC00 || value2 > 0xDFFF)
			return -1;

		value = value + (value2 & 0x3FF) + 0x10000;
		if (outLength) *outLength = 4;
		return value;
	}

	// It is an illegal sequence if a character in the 0xDC00-0xDFFF range comes first
	return -1;
}

GLFont::GLFontChar* GLFont::GetChar(int id)
{
	std::map<int, GLFontChar>::iterator it = header.chars.find(id);
	if (it == header.chars.end()) 
		return 0;

	return &it->second;
}

float GLFont::GetTextWidth(const char* text, int count)
{
	if (count <= 0)
		count = GetTextLength(text);

	float x = 0;

	for (int n = 0; n < count; )
	{
		int charId = GetTextChar(text, n, &n);

		GLFontChar* ch = GetChar(charId);
		if (ch == 0) ch = &defChar;

		x += (ch->adv);
	}

	return x;
}

float GLFont::GetHeight()
{
	return header.font_height;
}

int GLFont::GetTextLength(const char* text)
{
	if (header.encoding == UTF16)
	{
		int textLen = 0;
		for (;;)
		{
			unsigned int len;
			int r = DecodeUTF16(&text[textLen], &len);
			if (r > 0)
				textLen += len;
			else if (r < 0)
				textLen++;
			else
				return textLen;
		}
	}

	// Both UTF8 and standard ASCII strings can use strlen
	return (int)strlen(text);
}

int GLFont::GetTextChar(const char* text, int pos, int* nextPos)
{
	int ch;
	unsigned int len;
	if (header.encoding == UTF8)
	{
		ch = DecodeUTF8(&text[pos], &len);
		if (ch == -1) len = 1;
	}
	else if (header.encoding == UTF16)
	{
		ch = DecodeUTF16(&text[pos], &len);
		if (ch == -1) len = 2;
	}
	else
	{
		len = 1;
		ch = (unsigned char)text[pos];
	}

	if (nextPos) *nextPos = pos + len;
	return ch;
}

int GLFont::FindTextChar(const char* text, int start, int length, int ch)
{
	int pos = start;
	int nextPos;
	int currChar = -1;
	while (pos < length)
	{
		currChar = GetTextChar(text, pos, &nextPos);
		if (currChar == ch)
			return pos;
		pos = nextPos;
	}

	return -1;
}


//End of file


